Skip to content

feat(cli): add ui-next Solid/OpenTUI TUI stack#11248

Open
hannesrudolph wants to merge 3 commits intomainfrom
feat/cli-ui-next-opentui
Open

feat(cli): add ui-next Solid/OpenTUI TUI stack#11248
hannesrudolph wants to merge 3 commits intomainfrom
feat/cli-ui-next-opentui

Conversation

@hannesrudolph
Copy link
Collaborator

@hannesrudolph hannesrudolph commented Feb 6, 2026

Summary

Adds a new SolidJS/OpenTUI-based ui-next runtime for the CLI and wires the run command to launch the prebuilt bundle.

Changes

  • Add a new ui-next application layer with routes, contexts, components, and utility modules.
  • Add tests for autocomplete triggers, extension context behavior, spinner behavior, and terminal/editor/clipboard utilities.
  • Add a build entrypoint script and package script to bundle src/ui-next/main.tsx into dist/ui-next/main.js.
  • Update CLI run startup to resolve and dynamically import the built ui-next bundle.
  • Update dependencies, TypeScript config, tsup config, and lockfile for Solid/OpenTUI support.

Important

Introduces a new SolidJS/OpenTUI-based TUI stack for the CLI, adding new components, contexts, utilities, and tests, while updating the build process.

  • Behavior:
    • Adds ui-next runtime using SolidJS/OpenTUI for CLI TUI.
    • Updates run() in run.ts to dynamically import and start the TUI.
    • New startTUI() function in main.tsx to initialize TUI.
  • Components:
    • Adds App, Home, Session, Prompt, Logo, Tips, SessionHeader, SessionFooter, ChatMessage, ApprovalPrompt, FollowupPrompt, AutocompleteOverlay, HelpOverlay, HorizontalLine, DialogOverlay, ToastDisplay components.
    • Implements autocomplete, border, help-overlay, logo, prompt, tips, dialog, spinner, toast components.
  • Context:
    • Adds ThemeProvider, RouteProvider, ExitProvider, ToastProvider, KeybindProvider, DialogProvider, ExtensionProvider contexts.
    • Implements createSimpleContext() in helper.tsx for context creation.
  • Utilities:
    • Adds clipboard.ts, editor.ts, terminal.ts for clipboard, editor, and terminal utilities.
    • Implements getTerminalBackgroundColor(), copyToClipboard(), openEditor() functions.
  • Tests:
    • Adds tests for logo-data, triggers, extension, spinner, clipboard, editor, terminal utilities.
    • Tests for detectTrigger(), formatRelativeTime(), truncateText(), getReplacementText() in triggers.test.ts.
  • Build:
    • Adds build-ui-next.ts script for building TUI with Bun.
    • Updates package.json and tsup.config.ts for new dependencies and build process.
    • Adds tsconfig.ui-next.json for TUI-specific TypeScript configuration.

This description was created by Ellipsis for 88092ec. You can customize this summary. It will automatically update as commits are pushed.

@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. UI/UX UI/UX related or focused labels Feb 6, 2026
@roomote
Copy link
Contributor

roomote bot commented Feb 6, 2026

Rooviewer Clock   See task

Sync review of 3c42178 (lockfile update after removing React/Ink deps). No new issues found -- the lockfile changes are consistent with package.json. The 3 previously flagged issues remain open.

  • run.ts:205 -- TUI bundle path resolution (path.resolve(__dirname, ".."))) is incorrect in dev mode; resolves to src/commands/ instead of the CLI package root
  • autocomplete-handlers.ts:101-104 -- handleAutocompleteDismiss clears the entire textarea on Escape, discarding all user-typed text before the trigger character
  • editor.ts:20 -- execSync with string interpolation breaks on $EDITOR paths with spaces; should use execFileSync with an args array
Previous reviews

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

{ exitOnCtrlC: false },
)
// Resolve the ui-next bundle path relative to CLI package root
const cliRoot = process.env.ROO_CLI_ROOT || path.resolve(__dirname, "..")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cliRoot resolves incorrectly in dev mode. __dirname here points to src/commands/cli/, so path.resolve(__dirname, "..") yields src/commands/ -- not the CLI package root. This means tuiBundlePath resolves to src/commands/dist/ui-next/main.js, which doesn't exist. The bundled (tsup) case works because __dirname is dist/, going up one lands at the package root. The existing extension-host.ts solves this with findCliPackageRoot() (walks up to the nearest package.json); the same approach would work here.

Suggested change
const cliRoot = process.env.ROO_CLI_ROOT || path.resolve(__dirname, "..")
const cliRoot = process.env.ROO_CLI_ROOT || findCliPackageRoot(__dirname)

Fix it with Roo Code or mention @roomote and request a fix.

Comment on lines 296 to 306
function handleAutocompleteDismiss() {
batch(() => {
setActiveTrigger(null)
setShowHelp(false)
setAutocompleteItems([])
})
// Clear trigger char from input
if (textareaRef) {
textareaRef.clear()
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dismissing the autocomplete overlay (via Escape or Ctrl+C) calls textareaRef.clear(), which erases the entire input. If a user types look at @fi and then presses Escape to dismiss the file autocomplete, they lose "look at " as well. The comment says "Clear trigger char from input" but the code clears everything. Consider either leaving the text as-is on dismiss (just clear autocomplete state), or removing only the trigger portion (@fi) while preserving the text before it.

Fix it with Roo Code or mention @roomote and request a fix.


try {
writeFileSync(tmpFile, initialContent, "utf-8")
execSync(`${editor} ${tmpFile}`, { stdio: "inherit" })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using string interpolation in execSync means editors whose paths contain spaces or shell metacharacters (e.g. $EDITOR="/Applications/My Editor.app/...") will break or behave unexpectedly. Using execFileSync(editor, [tmpFile], { stdio: "inherit" }) avoids shell interpretation entirely and handles paths with spaces correctly.

Suggested change
execSync(`${editor} ${tmpFile}`, { stdio: "inherit" })
execFileSync(editor, [tmpFile], { stdio: "inherit" })

Fix it with Roo Code or mention @roomote and request a fix.

…cy UI

- Delete entire src/ui/ directory (~80 files of React/Ink components, hooks, stores)
- Remove react, ink, @inkjs/ui, zustand, @types/react, ink-testing-library deps
- Move @opentui/core-darwin-arm64 to optionalDependencies with all 5 platform variants
- Remove unused opentui-spinner dependency
- Chain build scripts: 'build' now runs tsup && bun build-ui-next.ts
- Clean tsup.config.ts: restore clean:true, remove React JSX config
- Clean tsconfig.json: remove jsx/jsxImportSource React settings

Architecture improvements:
- Decompose prompt God Component (502→194 LOC + 5 extracted modules)
- Extract shared extension-logic.ts (295 LOC pure functions)
- Eliminate test harness duplication, fix missing todo handling bug
- Relocate tools.ts from ui/utils/ to lib/utils/
- Port onboarding from React/Ink to pure Node.js terminal prompts
- Type dynamic import with UINextModule interface
- Replace all 'as any' casts with precise types
- Fix context-window.ts broken @/ui/store.js import
- Fix all lint warnings (unused imports, prefer-const, no-control-regex)

Verification: tsc clean, 350 tests pass, zero React/Ink/Zustand references, lint clean
@ellipsis-dev
Copy link
Contributor

ellipsis-dev bot commented Feb 7, 2026

⚠️ This PR is too big for Ellipsis, but support for larger PRs is coming soon. If you want us to prioritize this feature, let us know at help@ellipsis.dev


Generated with ❤️ by ellipsis.dev

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files. UI/UX UI/UX related or focused

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant